/**
 * @file app_udisk.cpp
 * @author Forairaaaaa
 * @brief
 * @version 0.1
 * @date 2023-11-04
 *
 * @copyright Copyright (c) 2023
 *
 */
#include "app_udisk.h"
#include "spdlog/spdlog.h"
#include "../../hal/hal.h"
#include "../assets/theme/theme.h"

#include <SD.h>
#include "USB.h"
#include "USBMSC.h"

using namespace MOONCAKE::APPS;

static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize);
static int32_t onRead(uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize);
static bool onStartStop(uint8_t power_condition, bool start, bool load_eject);

USBMSC MSC;

int m_sector_size = 0;
int m_sector_count = 0;

// Like setup()...
void AppUdisk::onResume()
{
    if (!HAL::CheckSdCard())
        HAL::PopFatalError("没SD卡呢亲");

    HAL::DisplayPageString(75, 100, "U盘模式");

    m_sector_size = SD.sectorSize();
    m_sector_count = SD.numSectors();
    // logSerial.printf("Card m_sector_size: %d\n", m_sector_size);
    // logSerial.printf("Card m_sector_count: %d\n", m_sector_count);

    USB.manufacturerName("Robomaster");
    USB.productName("Unilog");
    USB.serialNumber("22635213");

    MSC.vendorID("ESP32");      // max 8 chars
    MSC.productID("Unilog");   // max 16 chars
    MSC.productRevision("1.0"); // max 4 chars
    MSC.onStartStop(onStartStop);
    MSC.onRead(onRead);
    MSC.onWrite(onWrite);
    MSC.mediaPresent(true);
    MSC.begin(m_sector_count, m_sector_size);
    USB.begin();

    spdlog::info("{} onResume", getAppName());
}

// Like loop()...
void AppUdisk::onRunning()
{
    if (HAL::GetButton(GAMEPAD::BTN_B))
    {
        destroyApp();
    }

    HAL::Delay(1);
}

void AppUdisk::onDestroy()
{
    spdlog::info("{} onDestroy", getAppName());

    MSC.end();

    ESP.restart();
}

//-----------------------------------------------------------------------------------------

bool writeSectors(uint8_t *src, size_t start_sector, size_t sector_count)
{
    bool res = true;
    for (int i = 0; i < sector_count; i++)
    {
        res = SD.writeRAW((uint8_t *)src, start_sector + i);
        if (!res)
        {
            break;
        }
        src += m_sector_size;
    }
    return res;
}

static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize)
{
    // logSerial.printf("MSC WRITE: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
    // memcpy(msc_disk[lba] + offset, buffer, bufsize);
    if (writeSectors(buffer, lba, bufsize / m_sector_size))
    {
        return bufsize;
    }
    return bufsize;
}

bool readSectors(uint8_t *dst, size_t start_sector, size_t sector_count)
{
    bool res = true;
    for (int i = 0; i < sector_count; i++)
    {
        res = SD.readRAW((uint8_t *)dst, start_sector + i);
        if (!res)
        {
            break;
        }
        dst += m_sector_size;
    }
    return res;
}

static int32_t onRead(uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize)
{
    // logSerial.printf("MSC READ: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
    // memcpy(buffer, msc_disk[lba] + offset, bufsize);
    if (readSectors((uint8_t *)buffer, lba, bufsize / m_sector_size))
    {
        return bufsize;
    }
    return -1;
}

static bool onStartStop(uint8_t power_condition, bool start, bool load_eject)
{
    // logSerial.printf("MSC START/STOP: power: %u, start: %u, eject: %u\n", power_condition, start, load_eject);
    return true;
}
